package dp.util;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.zip.GZIPOutputStream;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ServletUtil {
	private static final Logger logger = LoggerFactory.getLogger(ServletUtil.class);
	public static final String CONTENTTYPE_HTML = "text/html";
    public static final String CONTENTTYPE_JSON = "application/json";
    public static final String CHARTSET_UTF8 = "utf-8";
    public static final String CHARTSET_GBK = "gbk";
    
    //是否启用gzip
    public static boolean gzipEnabled = true;
    //gzip的阈值，默认2048，即2k
    public static int gzipMinSize = 2048;
    
    /**
     * 取web目录的绝对路径,以文件分隔符结尾
     * @return
     */
    public static String getAppPath(ServletContext servletContext) {
        String path = servletContext.getRealPath("/");
        //在部分服务器下，比如websphere、weblogic下面不带分隔符
        if(!path.endsWith(File.separator)){
        	path += File.separator;
        }
        return path;
    }
    
	/**
     * 判断浏览器是否支持 gzip 压缩  ，如果服务器配置不使用gzip，或者客户端指定gzip=0则也不使用gzip压缩
     * @return
     */
    private static boolean isGzipSupport(HttpServletRequest request) {
        String headEncoding = request.getHeader("accept-encoding");  
        // 客户端 不支持 gzip,服务器配置不使用gzip，客户端要求不使用gzip
        if (headEncoding == null || (headEncoding.indexOf("gzip") == -1) || !gzipEnabled || "0".equals(request.getParameter("gzip"))) {  
            return false;  
        } 
        // 支持 gzip 压缩  
        else {
            return true;  
        }  
    }  
    
    /**
     * 向HttpServletResponse输出文本
     * @param text 输出的字符串
     * @param contentType 类型
     * @param charset 编码
     */
    public static void outputText(HttpServletRequest request, HttpServletResponse response, String text, String contentType, String charset) {
    	response.setCharacterEncoding(charset);
        //指定内容类型
    	response.setContentType(contentType + ";charset=" + charset);
        //禁止缓存
    	response.setHeader("Pragma", "no-cache");
    	response.setHeader("Cache-Control", "no-cache");
    	response.setDateHeader("Expires", 0);
        try {
        	//支持gzip，且长度大于指定阀值的时候
        	text = StringUtils.isBlank(text)?"":text;
        	byte[] content = text.getBytes(charset);
        	if (isGzipSupport(request) && content.length>=gzipMinSize) {
        		response.setHeader("content-encoding", "gzip");
        		OutputStream o = response.getOutputStream();
        		GZIPOutputStream gz = new GZIPOutputStream(o);
        		gz.write(content); 
        		gz.finish();
        		gz.close();
        		o.close();
        	}
        	else{
        		OutputStream o = response.getOutputStream();
        		o.write(content);
        		o.close();
        	}
        } catch (IOException e) {
        	logger.error("outputText error", e);
        }
    }
    
    /**
     * 向HttpServletResponse输出文件，此方法完成后并不关闭InputStream，需要自行在外面通过IOUtils.closeQuietly关闭
     * @param fileName
     * @param input
     * @param inline,直接打开还是下载，如果为true则直接打开，否则下载
     */
    public static void outputFile(HttpServletRequest request, HttpServletResponse response, String fileName, InputStream input, boolean inline) throws IOException{
        String filetype = FilenameUtils.getExtension(fileName);
        String name = StringUtils.isBlank(fileName)?"":URLEncoder.encode(fileName,"UTF-8");
        
        OutputStream output = response.getOutputStream();
        //inline--直接打开  attachment--下载
        response.setHeader("Content-Disposition", inline?"inline":"attachment" + "; filename=" + name);//下载
        response.setContentType(MIMEUtil.getMIMEType(filetype));
    	//如果是文件流，支持断点续传
        if(input instanceof FileInputStream){
        	//得到文件大小，不能用input.available()
        	long fSize = ((FileInputStream) input).getChannel().size();
        	 //下载起始位置  
            long since=0;  
            //下载结束位置  
            long until = fSize - 1; 
        	//获取Range，下载范围  
            String range=request.getHeader("range"); 
        	if(range != null){
        		// 若客户端传来Range，说明之前下载了一部分，设置206状态(SC_PARTIAL_CONTENT)
        		response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
                //剖解range  
                range=range.split("=")[1];  
                String[] rs = range.split("-");  
                if(StringUtils.isNumeric(rs[0])){  
                    since = Long.parseLong(rs[0]);  
                }  
                if(rs.length>1 && StringUtils.isNumeric(rs[1])){  
                    until = Long.parseLong(rs[1]);  
                }  
        	}
        	
        	//设置响应头 
            response.setHeader("Accept-Ranges", "bytes");  
            response.setHeader("Content-Range", "bytes "+since+"-"+ until + "/" + fSize);  
            response.setHeader("Content-Length", (until-since+1)+"");
            IOUtils.copyLarge(input, output, since, until-since+1);
        }
        else{
        	IOUtils.copy(input, output);
        }
        //输出  
        output.flush();  
        output.close(); 
    }
    
    /** 
     * 获取网络ip 
     * @param request 
     * @return 
     */  
    public static String getIpAddr(HttpServletRequest request){  
        String ipAddress = request.getHeader("x-forwarded-for");  
            if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {  
                ipAddress = request.getHeader("Proxy-Client-IP");  
            }  
            if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {  
                ipAddress = request.getHeader("WL-Proxy-Client-IP");  
            }  
            if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {  
                ipAddress = request.getRemoteAddr();  
            }  
            //对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割  
            if(ipAddress!=null && ipAddress.length()>15){ //"***.***.***.***".length() = 15  
                if(ipAddress.indexOf(",")>0){  
                    ipAddress = ipAddress.substring(0,ipAddress.indexOf(","));  
                }  
            }  
            return ipAddress;   
    }  
}
